#pragma once

#include "LinearSolver.h"
#include <functional>
#include <vector>
#include <deque>

namespace Calculus
{
    using Func11 = std::function<Real(Real)>;                                   // 一元函数 R -> R
    using FuncX1 = std::function<Real(LinearAlgebra::Vector)>;                  // 多元函数 Rn -> R
    using Func1X = std::function<LinearAlgebra::Vector(Real)>;                  // 一元向量函数 R -> Rn
    using FuncXX = std::function<LinearAlgebra::Vector(LinearAlgebra::Vector)>; // 多元向量函数 Rn -> Rm

    /**
     * @file Polynomial.h
     * @author xingyifan
     * @date 2022-11-30 16:04
     *
     * @description: 多项式类型
     */

    class Polynomial
    {
    protected:
        std::vector<Real> m_coefficients; // 系数向量

    public:
        /**
         * @file Polynomial.h
         * @author xingyifan
         * @date 2022-07-26 13:34
         *
         * @description: 构造器，允许阶数为 0
         */

        explicit Polynomial(int o = 0);            // 限定显式调用，防止 operator* 中的隐式转换
        Polynomial(std::initializer_list<Real> l); // 初始化列表构造
        Polynomial(std::vector<Real> &v);          // 向量构造
        Polynomial(const Polynomial &poly);        // 拷贝构造

        /**
         * @file Polynomial.h
         * @author xingyifan
         * @date 2022-07-26 13:35
         *
         * @description: 重载操作符
         */

        // 多项式赋值
        void operator=(const Polynomial &poly);

        // 多项式加减法
        Polynomial operator+(const Polynomial &poly) const;
        Polynomial operator-(const Polynomial &poly) const;

        // 多项式乘常数
        Polynomial operator*(Real k) const;
        Polynomial operator/(Real k) const;

        Polynomial operator*(const Polynomial &poly) const; // 多项式相乘
        Polynomial operator/(const Polynomial &poly) const; // 带余除法，获得商多项式

        Real operator()(Real x) const; // 多项式求值

        /**
         * @file Polynomial.h
         * @author xingyifan
         * @date 2022-07-27 15:46
         *
         * @description: 多项式操作
         */

        void push(Real k);                    // 推入高阶项
        void reduce();                        // 多项式降阶，将系数为 0 的高阶项去除
        Real intergral(Real a, Real b) const; // 定积分
        Polynomial intergral() const;         // 不定积分
        Polynomial derivative() const;        // 导函数

        /**
         * @file Polynomial.h
         * @author xingyifan
         * @date 2022-07-26 13:36
         *
         * @description: 获得多项式信息
         */

        int order() const;       // 获取多项式的阶
        Real coeff(int n) const; // 获得对应次数的系数

        // 多项式的拉普拉斯阵，为了方便起见，这里将矩阵取负，这样通过幂法解出的最大特征值就是多项式的根
        LinearAlgebra::Matrix Laplace() const;
    };

    /**
     * @file Calculus.h
     * @author xingyifan
     * @date 2022-12-02 09:55
     *
     * @description: 分段多项式
     */

    class PiecewisePolynomial
    {
    protected:
        std::deque<Real> m_interval;   // 分段区间端点
        std::deque<Polynomial> m_poly; // 多项式列表，数量是端点数 +1，包括左右半开区间上的多项式

    public:
        /**
         * @file Calculus.h
         * @author xingyifan
         * @date 2022-12-02 09:58
         *
         * @description: 分段构造
         */

        PiecewisePolynomial(Polynomial poly = Polynomial(0));                          // 没有区间端点，只有一个多项式
        PiecewisePolynomial(const PiecewisePolynomial &ppoly);                         // 拷贝构造
        PiecewisePolynomial(std::deque<Real> &interval);                               // 只设置区间，每段区间上是零
        PiecewisePolynomial(std::deque<Real> &interval, std::deque<Polynomial> &poly); // 设置区间和多项式

        /**
         * @file Calculus.h
         * @author xingyifan
         * @date 2022-12-02 10:17
         *
         * @description: 重载操作符
         */

        // 多项式赋值
        void operator=(const PiecewisePolynomial &poly);

        // 多项式加减法
        PiecewisePolynomial operator+(const PiecewisePolynomial &poly) const;
        PiecewisePolynomial operator-(const PiecewisePolynomial &poly) const;
        PiecewisePolynomial operator+(const Polynomial &poly) const;
        PiecewisePolynomial operator-(const Polynomial &poly) const;

        // 多项式乘常数
        PiecewisePolynomial operator*(Real k) const;
        PiecewisePolynomial operator/(Real k) const;

        PiecewisePolynomial operator*(const PiecewisePolynomial &poly) const; // 多项式相乘
        PiecewisePolynomial operator*(const Polynomial &poly) const;          // 多项式相乘
        PiecewisePolynomial operator/(const Polynomial &poly) const;          // 多项式除法

        Real operator()(Real x) const; // 多项式求值

        /**
         * @file Calculus.h
         * @author xingyifan
         * @date 2022-12-02 10:28
         *
         * @description: 元素操作
         */

        void push_back(Real t);  // 在右端添加端点，增加一个零多项式
        void push_front(Real t); // 在左端添加端点，增加一个零多项式

        Polynomial operator[](int i) const; // 获得指定索引的多项式
        Polynomial &operator[](int i);      // 获得指定索引的多项式引用
        Polynomial poly(Real t) const;      // 获得传入点对应的多项式

        int size() const;       // 获得端点数
        int order(int i) const; // 获得指定索引的阶数

        /**
         * @file Calculus.h
         * @author xingyifan
         * @date 2022-12-02 10:50
         *
         * @description: 多项式操作
         */

        PiecewisePolynomial intergral() const;  // 不定积分
        PiecewisePolynomial derivative() const; // 导函数

        int continuity(int i) const; // 检查端点处的连续性
        int continuity() const;      // 整体连续性

        friend PiecewisePolynomial merge(const PiecewisePolynomial &p1, const PiecewisePolynomial &p2); // 合并两个分段多项式
    };

    /**
     * @file Calculus.h
     * @author xingyifan
     * @date 2022-12-01 22:17
     *
     * @description: Jacobi 算子
     */

    class Jacobian
    {
    public:
        LinearAlgebra::Matrix operator()(FuncXX f, const LinearAlgebra::Vector &x); // 多元向量函数的 Jacobi 矩阵
        LinearAlgebra::Matrix operator()(FuncX1 f, const LinearAlgebra::Vector &x); // 多元函数的 Jacobi 矩阵
        LinearAlgebra::Vector operator()(Func1X f, Real x);                         // 一元向量函数的导向量
        Real operator()(Func11 f, Real x);                                          // 一元函数的导数
    };

    /**
     * @file Calculus.h
     * @author xingyifan
     * @date 2022-12-01 23:57
     *
     * @description: 积分器
     */

    class Integrator
    {
    protected:
        LinearAlgebra::Vector m_weight; // 积分权

    public:
        /**
         * @file Calculus.h
         * @author xingyifan
         * @date 2022-12-02 00:02
         *
         * @description: 初始化积分权
         */

        Integrator(int N);

        /**
         * @file Calculus.h
         * @author xingyifan
         * @date 2022-07-28 00:11
         *
         * @description: 一元函数积分
         */

        virtual Real operator()(Func11 f, Real a, Real b) = 0;

        /**
         * @file Calculus.h
         * @author xingyifan
         * @date 2022-12-01 23:43
         *
         * @description: 获得积分器的分割数
         */

        int order() const;
    };

    /**
     * @file Calculus.h
     * @author xingyifan
     * @date 2022-12-01 22:53
     *
     * @description: 牛顿积分器
     */

    class NewtonCotes : public Integrator
    {
    public:
        /**
         * @file Calculus.h
         * @author xingyifan
         * @date 2022-07-28 00:18
         *
         * @description: 在构造函数中初始化权重
         */

        NewtonCotes(int N);

        /**
         * @file Calculus.h
         * @author xingyifan
         * @date 2022-07-28 00:11
         *
         * @description: 一元函数积分
         */

        virtual Real operator()(Func11 f, Real a, Real b);
    };

    /**
     * @file Calculus.h
     * @author xingyifan
     * @date 2022-12-01 23:53
     *
     * @description: 高斯积分器
     */

    class GaussIntegrator : public Integrator
    {
    public:
        LinearAlgebra::Vector m_node; // 积分节点

    public:
        /**
         * @file Calculus.h
         * @author xingyifan
         * @date 2022-12-01 23:54
         *
         * @description: 构造初始化权和节点
         */

        GaussIntegrator(int N);

        /**
         * @file Calculus.h
         * @author xingyifan
         * @date 2022-12-01 23:55
         *
         * @description: 一元函数积分
         */

        virtual Real operator()(Func11 f, Real a, Real b);
    };

    /**
     * @file Calculus.h
     * @author xingyifan
     * @date 2022-12-01 22:14
     *
     * @description: 求解多元隐式方程的根
     */

    class FSolve
    {
    public:
        Real operator()(Func11 f, Real x);                   // 一元函数的根
        void operator()(FuncXX f, LinearAlgebra::Vector &x); // 多元函数求根
    };

    /**
     * @file Calculus.h
     * @author xingyifan
     * @date 2022-12-01 22:18
     *
     * @description: 特殊的生成算法
     */

    Real factorial(int n);                                                      // 阶乘
    Real combine(int n, int i);                                                 // 组合数
    Polynomial power(const Polynomial &poly, int n);                            // 多项式整数幂
    Polynomial nodes(LinearAlgebra::Vector &c);                                 // 产生节点多项式
    Polynomial Lagrange(LinearAlgebra::Vector &c, int j);                       // 已知节点 c0 c1 ... cn ，获得 cj 对应的初等多项式
    Polynomial interpolate(LinearAlgebra::Vector &x, LinearAlgebra::Vector &f); // 多项式插值
    Polynomial Legendre(int s);                                                 // Gauss-Legendre 多项式
    Polynomial Bernstein(int n, int i);                                         // 获得 Bernstein 基函数
    PiecewisePolynomial BasicBspline(std::deque<Real> &knot);                   // 获得 B 样条基函数
};